package com.itheima.utils;

import com.itheima.User;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Executor {

    private Configuration configuration;

    public Executor(Configuration configuration) {
        this.configuration = configuration;
    }

    public <E> List<E> selectList(String sql, String resultType) throws Exception {

        Connection connection = this.configuration.getDataSource().getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();

        List<E> list = new ArrayList<E>(resultSet.getRow());
        Class<E> clazz = (Class<E>) Class.forName(resultType);
        while(resultSet.next()) {
            int columnCount = metaData.getColumnCount();
            E instance = clazz.newInstance();
            for(int i=1;i<=columnCount;i++) {
                String columnName = metaData.getColumnName(i);
                Object object = resultSet.getObject(columnName);
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, clazz);
                Method writeMethod = propertyDescriptor.getWriteMethod();

                Class<?> aClass = writeMethod.getParameterTypes()[0];
                writeMethod.invoke(instance, object);
            }
            list.add(instance);
        }

        return list;
    }


    public <E> E selectOne(String sql, String resultType, Object ... parameters) throws Exception {

        ArrayList<String> colums = new ArrayList<>();
        Pattern pattern = Pattern.compile("#\\{\\w+\\}");
        Matcher matcher = pattern.matcher(sql);
        while (matcher.find()) {
            colums.add(matcher.group());
        }

        for (int i=0;i<colums.size();i++) {
            System.out.println(colums.get(i));
            sql = sql.replace(colums.get(i), "?");
        }

        System.out.println(sql);
        Connection connection = this.configuration.getDataSource().getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);


        for (int i=1;i<=colums.size();i++) {
            System.out.println("colums.size--->"+colums.size());
            preparedStatement.setObject(i, parameters[i-1]);
        }

        Class<?> clazz = Class.forName(resultType);
        E e = (E) clazz.newInstance();
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        while(resultSet.next()) {
            int columnCount = metaData.getColumnCount();
            for (int i=1;i<=columnCount;i++) {
                String columnName = metaData.getColumnName(i);
                Object object = resultSet.getObject(columnName);

                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, clazz);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(e, object);
            }
        }

        return e;
    }

    //insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    public void insert(String sql, Object pojo) throws Exception {

        Connection connection = this.configuration.getDataSource().getConnection();

        Pattern pattern = Pattern.compile("#\\{\\w+\\}");
        Matcher matcher = pattern.matcher(sql);

        List<String> params = new ArrayList<>();
        while(matcher.find()) {
            String group = matcher.group();
            params.add(group);
        }

        for(String param : params) {
            sql = sql.replace(param, "?");
        }

        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for(int i=1;i<=params.size();i++) {
            String s = params.get(i - 1);
            String property = s.substring(2, s.length() - 1);
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, pojo.getClass());
            Object value = propertyDescriptor.getReadMethod().invoke(pojo);
            preparedStatement.setObject(i, value);
        }

        preparedStatement.execute();
    }

    //update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
    public void update(String sql, Object pojo) throws Exception {

        Connection connection = this.configuration.getDataSource().getConnection();

        List<String> params = new ArrayList<>();
        Pattern pattern = Pattern.compile("#\\{\\w+\\}");
        Matcher matcher = pattern.matcher(sql);
        while (matcher.find()) {
            params.add(matcher.group());
        }

        for(String param : params) {
            sql = sql.replace(param, "?");
        }

        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for(int i=1;i<=params.size();i++) {
            String s = params.get(i - 1);
            String property = s.substring(2, s.length()-1);
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, pojo.getClass());
            Object value = propertyDescriptor.getReadMethod().invoke(pojo);
            preparedStatement.setObject(i, value);
        }

        preparedStatement.execute();
    }


}
